package com.codegeek.framework.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.codegeek.common.constant.HttpStatus;
import com.codegeek.common.utils.SecurityUtils;
import com.codegeek.common.utils.ServletUtils;
import com.codegeek.framework.interceptor.annotation.RepeatSubmit;
import com.codegeek.framework.web.domain.AjaxResult;
import com.codegeek.project.common.Decode;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


/**
 * 防止重复提交拦截器
 *
 * @author codegeek
 */
@Component
public abstract class RepeatSubmitInterceptor extends HandlerInterceptorAdapter
{

    @Value("${codegeek.uaCheck}")
    private boolean uaCheck;

    @Value("${codegeek.sessionCheck}")
    private boolean sessionCheck;

    @Value("${codegeek.ipCheck}")
    private boolean ipCheck;

    @Value("${codegeek.requestTimeCheck}")
    private boolean requestTimeCheck;

    @Value("${codegeek.handleRequestTime}")
    private int handleRequestTime;

    private static String localIp = "127.0.0.1";

    private static Map<String,String> sessionMap = new HashMap<>();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        response.setHeader("Set-Cookie", "cookiename=cookievalue; path=/; Domain=domainvaule; Max-age=seconds; HttpOnly");
        if (handler instanceof HandlerMethod)
        {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
            String requestUri = request.getRequestURI();
            if(requestUri.indexOf("login")==-1&&requestUri.indexOf("captchaImage")==-1&&requestUri.indexOf("download")==-1&&requestUri.indexOf("import")==-1&&requestUri.indexOf("testEms")==-1) {
                String cookieSessionId = "";
                if(request.getCookies()!=null){
                    for(Cookie cookie :request.getCookies()){
                        if(cookie.getName().equals("JSESSIONID")){
                            cookieSessionId = cookie.getValue();
                        }
                    }
                }
//                System.out.println(
//                        "请求："+request.getRequestURI()
//                                +",sessionId:"+(request.getSession(false)==null?"":request.getSession(false).getId())
//                                +",cookie:"+cookieSessionId
//                                +",username:"+(request.getSession(false)==null?"":request.getSession(false).getAttribute("username")));

                //user-agent拦截
//                if(uaCheck) {
//                    String ua = request.getHeader("user-agent");
//                    if (uaMap.get(SecurityUtils.getUsername())==null||!ua.equals(uaMap.get(SecurityUtils.getUsername()).toString())) {
//                        AjaxResult ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED,"没有权限，请联系管理员授权");
//                        ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
//                        return false;
//                    }
//                }
                //session检验
                if(sessionCheck) {
                    String key1 = SecurityUtils.getUsername();
                    String key2 = SecurityUtils.getUsername()+"_temp";
                    if(requestUri.indexOf("getInfo")>-1){
                        sessionMap.put(key1,request.getSession().getId());
                    }
                    if(requestUri.indexOf("getRouters")>-1){
                        sessionMap.put(key2,request.getSession().getId());
                    }
                    if (request.getSession(false) == null||request.getSession(false).getAttribute("username")==null) {
                        if (sessionMap.get(key1) != null || sessionMap.get(key2) != null) {
                            if (!sessionMap.get(key1).equals(cookieSessionId) && !sessionMap.get(key2).equals(cookieSessionId)) {
                                AjaxResult ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED,"没有权限，请联系管理员授权");
                                ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                                return false;
                            }
                        }
                    } else {
                        if (!request.getSession(false).getAttribute("username").equals(SecurityUtils.getUsername())) {
                            AjaxResult ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED,"没有权限，请联系管理员授权");
                            ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                            return false;
                        }
                    }
                }
                //ip校验
                if(ipCheck){
                    String ip = getIPAddress(request);
                    if(!ip.equals(SecurityUtils.getLoginUser().getIpaddr())){
                        AjaxResult ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED,"没有权限，请联系管理员授权");
                        ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                        return false;
                    }
                }
                //接口请求时间校验
                if(requestTimeCheck) {
                    String authToken = request.getHeader("authToken");
                    String name = Decode.getValue(authToken.split(",")[0]);
                    Long time = Long.valueOf(Decode.getValue(authToken.split("_")[1])) / 1000;
                    Long now = System.currentTimeMillis() / 1000;
                    if (now - time > handleRequestTime || !name.equals(SecurityUtils.getUsername())) {
                        AjaxResult ajaxResult = AjaxResult.error(HttpStatus.UNAUTHORIZED,"没有权限，请联系管理员授权");
                        ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                        return false;
                    }
                }
            }
            if (annotation != null)
            {
                if (this.isRepeatSubmit(request))
                {
                    AjaxResult ajaxResult = AjaxResult.error("不允许重复提交，请稍后再试");
                    ServletUtils.renderString(response, JSONObject.toJSONString(ajaxResult));
                    return false;
                }
            }
            return true;
        }
        else
        {
            return super.preHandle(request, response, handler);
        }
    }


    /**
     * 验证是否重复提交由子类实现具体的防重复提交的规则
     *
     * @return
     * @throws Exception
     */
    public abstract boolean isRepeatSubmit(HttpServletRequest request);


    public static String getIPAddress(HttpServletRequest request) {
        String ip = null;

        //X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            //X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        //有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        //还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1")?localIp:ip;
    }


}
